/*****************************************************************************
*   spi.c:  source file for spi module
*		ver 1.0
******************************************************************************/
#include "me32g030.h"
#include "me32g030_spi.h"

extern uint32_t SystemCoreClock;
/*****************************************************************************
Function Name	SPI_Open
Function Definition	void SPI_Open(uint8_t framemode, uint8_t bitwidth, uint8_t master, uint8_t spionlymode)
Function Description	Initial SPI infterface 
Input Parameters	Framemode: SPI_FRAME/SSI_FRAME, current support SPI_FRAME only
Bitwidth: data size, from 4-bit to 16-bit
Master: selection of master or slave, SPI_MASTER/SPI_SLAVE
spionlymode: SPI_MODE0~SPI_MODE3
Return Value	No
Condition	No
Function called	-

*****************************************************************************/
void SPI_Open(SPI0_Type * spi,uint8_t framemode, uint8_t bitwidth, uint8_t master, uint8_t spionlymode)
{
	//enable SPI clock
  switch  ((uint32_t)spi)
	{
		case (uint32_t)SPI0:
			SYSCON->SYSAHBCLKCTRL_b.SPI0_CLK=1;
			SYSCON->PRESETCTRL_b .SPI0_RST_N=0;
			SYSCON->PRESETCTRL_b .SPI0_RST_N=1;
		break;
		case (uint32_t)SPI1:
			SYSCON->SYSAHBCLKCTRL_b.SPI1_CLK=1;
			SYSCON->PRESETCTRL_b .SPI1_RST_N=0;
			SYSCON->PRESETCTRL_b .SPI1_RST_N=1;	
		break;

		default:
			return;
	}
	//set spi frame SPI/SSI selcetion
	spi->CON_b.FRF=framemode;
	//select bit width
	spi->CON_b.DSS=bitwidth-1;
	//Set master/slave
	spi->CON_b.MS=master;

	//set SPI mode
	spi->CON_b.CPO=spionlymode;
	spi->CON_b.CPH=spionlymode>>1;
	
	//enable SPIcontroller
	spi->CON_b.SSPEN=1;
	
	return;
}
/*****************************************************************************
Function Name	SPI_Close
Function Definition	void SPI_Close(void)
Function Description	De-Initial SPI interface 
Input Parameters	No
Return Value	No
Condition	No
Function called	-

*****************************************************************************/
void SPI_Close(SPI0_Type * spi)
{
	//Disable SPI clock
//  switch  ((uint32_t)spi)
//	{
//		case (uint32_t)SPI0:
//			SYSCON->PCLKEN_b.SPI0_CLK=0;
//		break;
//		case (uint32_t)SPI1:
//			SYSCON->PCLKEN_b.SPI1_CLK=0;	
//		break;

//		default:
//		return;
//	}
	return;
}
/*****************************************************************************
Function Name	SPI_SetClk
Function Definition	void SPI_SetClk(uint32_t freq)
Function Description	Setup SPI clock. In Master mode, SPI frequency set no more than system clock divide by 7; 
												in Slave mode, the frequency set no more than system clock divide by 12.
Input Parameters	No
Return Value	No
Condition	No
Function called	-

*****************************************************************************/
void SPI_SetClk(SPI0_Type * spi,uint32_t freq)
{
	uint32_t div;
	uint8_t m,n;
	
	//FSSPCLK = PCLK / ((M+1)*N)
	//N is an even value from 2 to 254
	
	div=SystemCoreClock/freq;
	if (div<3) return; 
	
	//set up divider
	if (div<=4)
	{
		n=2;m=2;
	}else
	{
		n=(div>>2)<<1;
		if (n>254) 
		{
			n=254;
			m=254;
		}else
			m=div-n;
	}
	spi->CLK_b.N = n;
	spi->CLK_b.M = m-1;
	return;
}
/*****************************************************************************
Function Name	SPI_ClearFIFO
Function Definition	void SPI_ClearFIFO(void)
Function Description	Clear SPI TX and RX FIFO.
Input Parameters	No
Return Value	No
Condition	No
Function called	-

*****************************************************************************/
void SPI_ClearReceiveFIFO(SPI0_Type * spi)
{
	uint16_t data;
	//wait untile TX FIFO empty
	while(spi->STAT_b.BSY);

	/* Clear all remaining frames in RX FIFO */
	while (spi->STAT_b.RNE) {
		data=spi->DAT;
	}

	/* Clear status */
	SPI_ClrInt(spi);	
	
	return;
}
/*****************************************************************************
Function Name	SPI_SingleWriteRead
Function Definition	void SPI_SingleWriteRead(uint16_t *data)
Function Description	Write data to external SPI device and same time read same size data back from SPI device.
Input Parameters	No
Return Value	No
Condition	No
Function called	-

*****************************************************************************/
void SPI_SingleWriteRead(SPI0_Type * spi,uint16_t *data)
{
	SPI_ClearReceiveFIFO(spi);
	//Write data to FIFO
	spi->DAT=*data;
	//wait untile TX FIFO empty
	while(spi->STAT_b.BSY);
	//Read data from FIFO	
	*data=spi->DAT;
	return;
}
/*****************************************************************************
Function Name	SPI_Write
Function Definition	void SPI_Write (uint8_t *src, uint8_t noofdata)
Function Description	Write data to SPI FIFO, if FIFO full, stop with rest number of data and current data pointer
Input Parameters	*src: pointer to data
noofdata: number of data to send
Return Value	No
Condition	No
Function called	-

*****************************************************************************/
void SPI_Write (SPI0_Type * spi,uint8_t *src, uint8_t noofdata)
{

	while(noofdata!=0)
	{
	//wait untile TX FIFO empty
	//while(SPI_TX_FIFO_Not_Empty);
//	//clear RX FIFO
//	SPI->CR1_b.RSFR=1;
//	SPI->CR1_b.RSFR=0;
//	//Write data to FIFO
	if (spi->STAT_b.TNF)
	{
		spi->DAT=*src++;
		noofdata--;
	}
	//wait untile TX FIFO empty
//	while(SPI_TX_FIFO_Not_Empty);
//	//Read data from FIFO	
//	//*data=SPI->DR;
	
		
//		//Write data to FIFO
//		if (SPI->SR_b.TNF)
		
//		for(n=0;n<8;n++)
//		{			
//			SPI->DR=*src++;	
//			noofdata--;
//			if (noofdata==0)
//				break;
//		}
	}
	//wait untile TX FIFO empty
	while(spi->STAT_b.BSY);
	return;
}
/*****************************************************************************
Function Name	SPI_Read
Function Definition	void SPI_Read (uint8_t *dst, uint8_t noofdata)
Function Description	Read data from SPI FIFO.
Input Parameters	*dst: pointer to destination
noofdata: number of data read
Return Value	No
Condition	No
Function called	-

*****************************************************************************/
void SPI_Read (SPI0_Type * spi,uint8_t *dst, uint8_t noofdata)
{
	uint8_t notx,norx;
	notx=noofdata;norx=noofdata;
	//wait untile TX FIFO empty
	SPI_ClearReceiveFIFO(spi);

	while(notx!=0)
	{
		//Get data form FIFO
		if (spi->STAT_b.RNE)
		{
			*dst++=spi->DAT;
			norx--;
		}
		//Write data to FIFO
		if (spi->STAT_b.TNF)
		{			
			spi->DAT=0x00;	
			notx--;
		}
	}
	while(norx!=0)
	{
		//Get data form FIFO
		if (spi->STAT_b.RNE)
		{
			*dst++=spi->DAT;
			norx--;
		}
	}
	return;
}
/*****************************************************************************
Function Name	SPI_ClrInt(may not need)
Function Definition	void SPI_ClrInt(void)
Function Description	Clear SPI interrupt
Input Parameters	No
Return Value	No
Condition	No
Function called	-

*****************************************************************************/
void SPI_ClrInt(SPI0_Type * spi)
{
	spi->ICLR=0xFF;
}
/*****************************************************************************
Function Name	SPI_EnableInt
Function Definition	void SPI_EnableInt(uint8_t inttype)
Function Description	Setup SPI interrupt
Input Parameters	Inttype: combination of 
					SPI_RX_FIFO_FULL	1
					SPI_RX_FIFO_NOT_EMPTY	2
					SPI_RX_FIFO_HALF_FULL	4
					SPI_TX_FIFO_HALF_EMPTY	8
Return Value	No
Condition	No
Function called	-

*****************************************************************************/
void SPI_EnableInt(SPI0_Type * spi,uint8_t inttype)
{
	spi->IMSC |= inttype;
	return;
}
/*****************************************************************************
Function Name	SPI_DisableInt
Function Definition	void SPI_DisableInt(uint8_t inttype)
Function Description	Setup SPI interrupt
Input Parameters	Inttype: combination of 
					SPI_RX_FIFO_FULL	1
					SPI_RX_FIFO_NOT_EMPTY	2
					SPI_RX_FIFO_HALF_FULL	4
					SPI_TX_FIFO_HALF_EMPTY	8
Return Value	No
Condition	No
Function called	-

*****************************************************************************/
void SPI_DisableInt(SPI0_Type * spi,uint8_t inttype)
{
	spi->IMSC &= ~inttype;
	
	return;
}

/******************************************************************************
**                            End Of File
******************************************************************************/
